package cn.turboinfo.fuyang.api.provider.common.service.impl.category;

import cn.turboinfo.fuyang.api.domain.common.service.category.CategoryService;
import cn.turboinfo.fuyang.api.domain.common.service.file.FileAttachmentService;
import cn.turboinfo.fuyang.api.domain.web.component.file.FileRefTypeConstant;
import cn.turboinfo.fuyang.api.entity.common.pojo.category.Category;
import cn.turboinfo.fuyang.api.entity.common.pojo.file.FileAttachment;
import cn.turboinfo.fuyang.api.provider.common.repository.database.category.CategoryDAO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.category.CategoryPO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.sunshow.toolkit.core.qbean.helper.service.impl.DefaultQServiceImpl;
import nxcloud.foundation.core.data.support.annotation.EnableSoftDelete;
import nxcloud.foundation.core.util.TreeHelper;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@EnableSoftDelete
@Service
public class CategoryServiceImpl extends DefaultQServiceImpl<Category, Long, CategoryPO, CategoryDAO> implements CategoryService {

    private final FileAttachmentService fileAttachmentService;

    @SuppressWarnings("unchecked")
    private List<Category> buildTree(List<Category> categoryList) {

        Set<Long> categoryIdSet = categoryList.stream()
                .map(Category::getId)
                .collect(Collectors.toSet());

        Map<Long, FileAttachment> fileAttachmentMap = fileAttachmentService.findByRefIdInAndRefType(categoryIdSet, FileRefTypeConstant.CATEGORY_ICON)
                .stream()
                .collect(Collectors.toMap(FileAttachment::getRefId, o -> o, (o1, o2) -> o1));

        categoryList.forEach(category -> {
            if (fileAttachmentMap.containsKey(category.getId())) {
                category.setIconId(fileAttachmentMap.get(category.getId()).getId());
            }
        });

        return TreeHelper.buildTree(
                categoryList,
                Category::getId,
                Category::getParentId,
                (category, children) -> {
                    category.setChildren((List<Category>) children);
                    return null;
                },
                Comparator.comparing(Category::getSortValue)
        );
    }

    @Override
    public List<Category> findAllSortedWithHierarchy() {
        return buildTree(convertQBeanToList(dao.findAll()));
    }


    @Override
    public List<Category> findWithHierarchy(Collection<Long> categoryIdCollection) {
        return buildTree(convertQBeanToList(dao.findAllById(categoryIdCollection)));
    }

    @Override
    public List<Category> findByParentIdAndName(Long parentId, String name) {
        return convertQBeanToList(dao.findByParentIdAndNameOrderByIdDesc(parentId, name));
    }

    @Override
    public List<Category> findTop() {
        return convertQBeanToList(dao.findByParentIdOrderBySortValueAscIdAsc(0L));
    }

    @Override
    public boolean checkAvailable(Long parentId, String name) {
        return checkAvailable(null, parentId, name);
    }

    @Override
    public boolean checkAvailable(Long categoryId, Long parentId, String name) {
        return findByParentIdAndName(parentId, name)
                .stream()
                .allMatch(it -> it.getId().equals(categoryId));
    }

    @Override
    public List<Category> findByCodeWithChildren(String code) {
        List<CategoryPO> categoryPOList = dao.findByCode(code);
        Set<Long> categoryIdSet = categoryPOList.stream()
                .map(CategoryPO::getId)
                .collect(Collectors.toSet());

        categoryPOList.addAll(dao.findByParentIdIn(categoryIdSet));

        return convertQBeanToList(categoryPOList);
    }

    @Override
    public List<Category> findAllChildren() {
        return convertQBeanToList(dao.findAllByParentIdNot(0L));
    }

}
